package MAIN;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.security.Key;
import java.util.Arrays;
import java.util.Random;
import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.Mac;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.PBEKeySpec;
import javax.crypto.spec.PBEParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import sun.misc.BASE64Decoder;
import sun.misc.BASE64Encoder;

/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

/**
 *
 * @author Messi
 */
public class usc_sessionkey_mac {
    
    static final String AZ = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"
            + "abcdefghijklmnopqrstuvwxyz"
            + "!@#$%^&*()-_+=";
    static Random rnd = new Random();
    
    public static String randomString(int len)
    {
           StringBuilder sb = new StringBuilder( len );
            for( int i = 0; i < len; i++ ) 
            sb.append( AZ.charAt( rnd.nextInt(AZ.length()) ) );
            return sb.toString();
    }
    
    public static byte[] generateMAC(String inputString, String secreteKeyString) throws Exception
    {
        byte[] macBytes = null;
        //KeyGenerator keyGen = KeyGenerator.getInstance("HmacMD5");
        //SecretKey secretKey = keyGen.generateKey();
        byte[] encodedKey     = secreteKeyString.getBytes();
        SecretKey secretKey = new SecretKeySpec(encodedKey,0,encodedKey.length,"HmacSHA256");
        Mac mac = Mac.getInstance(secretKey.getAlgorithm());
        mac.init(secretKey);
        byte[] byteData = inputString.getBytes("UTF8");
        macBytes = mac.doFinal(byteData);
        return macBytes;
    }
    
    public static String xorMessage(String message, String key)
    {
       try 
       {
          if (message==null || key==null ) return null;
         char[] keys=key.toCharArray();
         char[] mesg=message.toCharArray();
         int ml=mesg.length;
         int kl=keys.length;
         char[] newmsg=new char[ml];
         for (int i=0; i<ml; i++){
            newmsg[i]=(char)(mesg[i]^keys[i%kl]);
         }//for i
         mesg=null; keys=null;
         return new String(newmsg);
      }
      catch ( Exception e ) 
      {
         return null;
      }  
    }//xorMessage

   public static final String DEFAULT_ENCODING="UTF-8"; 
   static BASE64Encoder enc=new BASE64Encoder();
   static BASE64Decoder dec=new BASE64Decoder();

   public static String base64encode(String text){
      try {
         String rez = enc.encode( text.getBytes( DEFAULT_ENCODING ) );
         return rez;         
      }
      catch (Exception e ) {
         return null;
      }
   }//base64encode

   public static String base64decode(String text){
         try {
            return new String(dec.decodeBuffer( text ),DEFAULT_ENCODING);
         }
         catch (Exception e ) {
           return null;
         }
      }//base64decode
   
   public static int Compare2MAC(byte[] mac1, byte[] mac2)
   {
       if(Arrays.equals(mac2, mac1))
           return 1;
       return 0;
   }
   
   //**http://stackoverflow.com/questions/5837698/converting-any-object-to-a-byte-array-in-java
   //Convert Object to byte[]
   public static byte[] serialize(Object obj) throws IOException {
        ByteArrayOutputStream b = new ByteArrayOutputStream();
        ObjectOutputStream o = new ObjectOutputStream(b);
        o.writeObject(obj);
        return b.toByteArray();
    }
   //Convert byte[] to Object
    public static Object deserialize(byte[] bytes) throws IOException, ClassNotFoundException {
        ByteArrayInputStream b = new ByteArrayInputStream(bytes);
        ObjectInputStream o = new ObjectInputStream(b);
        return o.readObject();
    }

   //**http://stackoverflow.com/questions/1132567/encrypt-password-in-configuration-files-java
   public static byte[] Encrypt(String secretKeyString, Object input) throws Exception
   {
       if(input==null || secretKeyString == null)
       {
           System.out.println("Dau vao null!");
       }
       byte[] re = null;
       byte[] data = serialize(input);
       char[] PASSWORD = secretKeyString.toCharArray();
       byte[] SALT = {
        (byte) 0xde, (byte) 0x33, (byte) 0x10, (byte) 0x12,
        (byte) 0xde, (byte) 0x33, (byte) 0x10, (byte) 0x12,
       };

       SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("PBEWithMD5AndDES");//PBEWithMD5AndDES
       SecretKey key = keyFactory.generateSecret(new PBEKeySpec(PASSWORD));
       Cipher pbeCipher = Cipher.getInstance("PBEWithMD5AndDES/CBC/PKCS5Padding");
       pbeCipher.init(Cipher.ENCRYPT_MODE, key, new PBEParameterSpec(SALT,20));
       re = pbeCipher.doFinal(data);
       return re;
   }
   public static Object Decrypt(String secretKeyString, byte[] input) throws Exception
   {       
       if(input==null || secretKeyString == null)
       {
           System.out.println("Dau vao null!");
       }
       Object re = null;       
       char[] PASSWORD = secretKeyString.toCharArray();
       byte[] SALT = {
        (byte) 0xde, (byte) 0x33, (byte) 0x10, (byte) 0x12,
        (byte) 0xde, (byte) 0x33, (byte) 0x10, (byte) 0x12,
       };
       SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("PBEWithMD5AndDES");
       SecretKey key = keyFactory.generateSecret(new PBEKeySpec(PASSWORD));
       Cipher pbeCipher = Cipher.getInstance("PBEWithMD5AndDES/CBC/PKCS5Padding");
       pbeCipher.init(Cipher.DECRYPT_MODE, key, new PBEParameterSpec(SALT, 20));
       byte[] temp1 = pbeCipher.doFinal(input);
       re = deserialize(temp1);
       return re;
   }
   
   
    public static void main(String[] args) throws Exception 
    {
        //Random String for Secrete Key (Session Key)
        String s1 = randomString(50);
        //System.out.println(s1);
       /*
       //Use Secrete Key to encrypt and decrypt
       String txt="Anh là ĐQM Dũng" ;
       String key = s1;
       System.out.println(txt+" XOR-ed to: "+(txt=xorMessage(txt,key)));
       String encoded=base64encode( txt );       
       System.out.println( " is encoded to: "+encoded+" and that is decoding to: "+ (txt=base64decode(encoded)));
       System.out.println( "XOR-ing back to original: "+xorMessage(txt,key));
       */
        
       /*
        //Use Secrete Key to create MAC
        s1 = "secreteKeySring";//
        byte[] b = generateMAC("ABC",s1);
        String s2 = new String(b,"UTF-8");
        String endcoded = base64encode(s2);
        System.out.println(endcoded);        
        //Compare 2 byte array (MAC)
        byte[] c = b;
        if(Compare2MAC(c, b)==1)
        {
            System.out.println("Two MAC is Equal.");
        }
        else
        {
            System.out.println("Two MAC is Not Equal.");
        }
        */
        
        String keyString = randomString(50);
        System.out.println("Plaintext: " + s1);
        System.out.println("KeyString: " + keyString);
        System.out.println("Encrypt & Decypt");
        System.out.println("Encrypt...");
        byte[] encrypt = Encrypt(keyString, s1);
        String decrypt = (String)Decrypt(keyString, encrypt);
        System.out.println("Decrypt: " + decrypt);
        System.out.println();
        
        
    }
    
}
